home *** CD-ROM | disk | FTP | other *** search
- /*
- * draw.c
- *
- * Drawing memory usage
- *
- * Copyright 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
-
- #include <gl/gl.h>
-
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <bstring.h>
-
- #include "process.h"
- #include "draw.h"
-
- #define FREEPID (-1) /* smaller than any valid pid */
- #define OTHERPID 0x00010000 /* bigger than any valid pid */
- #define IRIXPID 0x00010001 /* bigger than OTHERPID */
-
- #define FREECOLOR (GREEN + 8)
- #define IRIXCOLOR (MAGENTA + 8)
- /*
- * We want to use the color (0, 0x24, 0x3f) as the background. On 24
- * bit systems, we can access this at colormap index 97, but on 8 bit
- * systems we have to map it into the first 16 cells. 8 is one that
- * we're not using. See code in Init.
- */
- #define BGCOLOR 97
- #define BGCOLOR_4BIT 8
- #define TEXTCOLOR 15
-
- #define MARG_NUM 2
- #define BAR_NUM 5
- #define LABEL_NUM 13
- #define LINELEFT_NUM 8
- #define LINERIGHT_NUM 12
- #define DENOM 26
- #define YSHADOWOFF 25
- #define XSHADOWOFF 25
- #define MINWIDTH 600
- #define MINHEIGHT 600
- #define TEXTWIDTH 236
- #define SLABELWIDTH 88
-
- #define MIN(a,b) ((a) < (b) ? (a) : (b))
-
- Colorindex barColors[] = { YELLOW + 8, RED + 8, CYAN + 8, BLUE + 8,
- FREECOLOR, IRIXCOLOR };
-
- #define NCOLORS (sizeof barColors/sizeof *barColors - 2)
- #define FREEINDEX NCOLORS
- #define IRIXINDEX (NCOLORS + 1)
-
- static long winWidth, winHeight, barWidth, hmargin, barHeight;
- static long topMargin, bottomMargin;
- static long labelLeft, lineLeft, lineRight, memThresh;
- static long labelTop, labelBottom;
- static int textHeight, halfTextHeight;
- static Colorindex bgColor;
- static otherColor = -1;
- static PROGNAME *drawNames;
-
- static char *titles[] = {
- "Physical Memory Breakdown",
- "Resident Sizes of Processes",
- "Total Sizes of Processes",
- "Resident Mappings",
- };
-
- static char *progTitles[] = {
- "Physical Memory use for %s",
- "Resident Size of %s",
- "Total Size of %s",
- "Resident Mapping Breakdown of %s",
- };
-
- static char *captions[] = {
- "Physical Memory: %d K (%d K used)",
- "Sum of Resident Sizes: %d K",
- "Sum of Total Sizes: %d K",
- "Physical Memory: %d K (%d K used)",
- };
-
- static char *progCaptions[] = {
- "Physical Memory Use: %d K",
- "Resident Size: %d K",
- "Total Size: %d K",
- "Resident Mapping Breakdown: %d K",
- };
-
- static char *secondLabels[] = {
- "gmemusage bug!",
- "Private",
- "Shared",
- "Physical",
- "Resident",
- };
-
- /*
- * static int
- * WeWantThisOne(char *progName, long size)
- *
- * Description:
- * Given the name of a program and its size, determine whether to
- * display it separately. If we return 1, it will get its own
- * bar; if we return 0, it will get lumped in with a bunch of
- * others.
- *
- * The name check occurs if gmemusage was started with the -p
- * option. Otherwise, just the threshhold is checked.
- *
- * Parameters:
- * progName Name of program under consideration
- * size size of program under consideration
- *
- * Returns:
- * 1 if this program is to be displayed separately
- * 0 if this program is to be lumped with "other"
- */
-
- static int
- WeWantThisOne(char *progName, long size)
- {
- PROGNAME *name;
-
- if (drawNames) {
- name = drawNames;
-
- while (name) {
- if (strcmp(progName, name->name) == 0) {
- return 1;
- }
- name = name->next;
- }
- return 0;
- }
-
- return size >= memThresh;
- }
-
- /*
- * static PROGRAM *
- * FirstProgram(PROGRAM *prog)
- *
- * Description:
- * Find the first non-skip program in a list
- *
- * Parameters:
- * prog list of programs
- *
- * Returns:
- * first program in the list that doesn't have the skip flag set
- */
-
- static PROGRAM *
- FirstProgram(PROGRAM *prog)
- {
- while (prog && prog->skip) {
- prog = prog->next;
- }
-
- return prog;
- }
-
- /*
- * static PROGRAM *
- * NextProgram(PROGRAM *prog)
- *
- * Description:
- * Find the next non-skip program in a list
- *
- * Parameters:
- * prog list of prograsm
- *
- * Returns:
- * the next program in the list that doesn't have the skip
- * flag set
- */
-
- static PROGRAM *
- NextProgram(PROGRAM *prog)
- {
- if (!prog) {
- return NULL;
- }
-
- do {
- prog = prog->next;
- } while (prog && prog->skip);
-
- return prog;
- }
-
- /*
- * static PROGRAM *
- * PrevProgram(PROGRAM *prog)
- *
- * Description:
- * Find the previous non-skip rogram in a list
- *
- * Parameters:
- * prog list of programs
- *
- * Returns:
- * The previous program in the list that doesn't have the skip
- * flag set.
- */
-
- static PROGRAM *
- PrevProgram(PROGRAM *prog)
- {
- if (!prog) {
- return NULL;
- }
-
- do {
- prog = prog->prev;
- } while (prog && prog->skip);
-
- return prog;
- }
-
- /*
- * PROGRAM *
- * DrawSetup(PROGRAM *new, PROGRAM *old, long physMem, long freeMem,
- * UsageType type, SecondType stype, int all, int *barTotal,
- * int *numBars)
- *
- * Description:
- * Add a bar for free memory (Physical). Allocate colors
- * for each of the bars, add a bar for "other", and add a bar for
- * Irix (Physical).
- *
- * Parameters:
- * new The new list of programs to display as bars
- * old The last one displayed; we use this to keep the
- * colors consistent
- * physMem Amount of physical memory on the system
- * freeMem Amount of memory the kernel says is free
- * type Type of bars to display
- * stype Secondary type of bars to display
- * all 1 if this is all processes, 0 if this is a breakdown
- * for one process
- * barTotal gets total for the bar
- * numBars gets number of bars
- *
- * Returns:
- * The list of programs to display (same as new with some stuff
- * added)
- */
-
- PROGRAM *
- DrawSetup(PROGRAM *new, PROGRAM *old, long physMem, long freeMem,
- UsageType type, SecondType stype, int all, int *barTotal,
- int *numBars)
- {
- PROGRAM *prev = NULL, *prevColor = NULL, *head;
- long progTotal, otherMem = 0, userMem, otherSecondVal = 0;
- char otherBuf[100];
- int nBars;
-
- nBars = 0;
-
- progTotal = 0;
-
- if (type == Physical || type == MappedObjects) {
- if (all) {
- *barTotal = physMem;
- /*
- * Add the free chunk at the top
- */
- head = malloc(sizeof *head);
- /*
- * Be very, very careful here. FreeUsage will free
- * progName and mapName, but not manType!!
- */
- head->progName = strdup("Free");
- head->mapName = strdup("Free");
- head->mapType = "Free";
- head->value = freeMem;
- head->size = head->resSize = head->weightSize = head->privSize
- = head->value;
- head->secondValue = NOSVAL;
- head->color = FREEINDEX;
- head->pid = FREEPID;
- head->nProc = 1;
- head->skip = 0;
- head->special = 1;
- head->print = 1;
- nBars++;
-
- head->prev = NULL;
- head->next = new;
- new->prev = head;
- } else {
- head = new;
- }
- /*
- * Add up all the sizes
- */
- while (new) {
- progTotal += new->weightSize;
- new = new->next;
- }
- if (!all) {
- *barTotal = progTotal;
- }
- } else {
- head = new;
- while (new) {
- progTotal += type == Resident ? new->resSize : new->size;
- new = new->next;
- }
- *barTotal = progTotal;
- }
-
- userMem = progTotal;
- new = (type == Physical || type == MappedObjects)
- && all ? head->next : head;
-
- while (new) {
- /*
- * Set the values for each bar appropriately
- */
- switch (type) {
- case Physical:
- case MappedObjects:
- new->value = new->weightSize;
- break;
- case Resident:
- new->value = new->resSize;
- break;
- default:
- case Size:
- new->value = new->size;
- break;
- }
-
- switch (stype) {
- default:
- case None:
- new->secondValue = NOSVAL;
- break;
- case Priv:
- new->secondValue = new->privSize;
- break;
- case Shared:
- new->secondValue = new->weightSize - new->privSize;
- break;
- case Phys:
- new->secondValue = new->weightSize;
- break;
- case Res:
- new->secondValue = new->resSize;
- break;
- }
-
- /*
- * Set the skip flag, allocate colors (using the old list if
- * it's valid), and add up the amount to be displayed in the
- * "other" bar.
- */
- if (!all || WeWantThisOne(new->progName, new->value)) {
- new->skip = 0;
- new->special = 0;
- while (old && old->pid < new->pid) {
- old = old->next;
- }
-
- if (old && !old->skip && old->pid == new->pid) {
- new->color = old->color;
- } else if (prevColor) {
- new->color = (prevColor->color + 1) % NCOLORS;
- } else {
- new->color = 0;
- }
- prevColor = new;
- nBars++;
- } else {
- new->skip = 1;
- otherMem += new->value;
- otherSecondVal += new->secondValue;
- }
-
- prev = new;
- new = new->next;
- }
-
- /*
- * Add the other bar
- */
- if (otherMem) {
- /*
- * The check for old resets other color if the rest of the
- * bars are also getting reset
- */
- if (otherColor == -1 || !old) {
- otherColor = prevColor ? (prevColor->color + 1) % NCOLORS : 0;
- }
- new = malloc(sizeof *new);
- if (!drawNames) {
- sprintf(otherBuf, "< %d", memThresh);
- }
- new->progName = strdup(drawNames ? "Other" : otherBuf);
- new->mapName = NULL;
- new->value = otherMem;
- new->secondValue = otherSecondVal;
- new->pid = OTHERPID;
- new->color = otherColor;
- new->next = NULL;
- new->prev = prev;
- new->skip = 0;
- new->special = 1;
- new->print = 0;
- new->nProc = 1;
- prev->next = new;
- prev = new;
- nBars++;
- }
-
- if ((type == Physical || type == MappedObjects) && all) {
- /*
- * Add the Irix chunk at the bottom
- */
- if (prev) {
- new = malloc(sizeof *new);
- /*
- * Be very, very careful here. FreeUsage will free
- * progName and mapName, but not manType!!
- */
- new->progName = strdup(IRIX);
- new->mapName = strdup(IRIX);
- new->mapType = IRIX;
- new->value = physMem - userMem - freeMem;
- new->size = new->resSize = new->weightSize = new->privSize
- = new->value;
- new->secondValue = NOSVAL;
- new->color = IRIXINDEX;
- new->pid = IRIXPID;
- new->nProc = 1;
- new->next = NULL;
- new->prev = prev;
- new->skip = 0;
- new->special = 0;
- new->print = 1;
- prev->next = new;
- nBars++;
- }
- }
-
- *numBars = nBars;
- return head;
- }
-
- /*
- * void
- * Resize(void)
- *
- * Description:
- * This sets some global variables based on the size of the window.
- */
-
- void
- Resize(void)
- {
- reshapeviewport();
- getsize(&winWidth, &winHeight);
- ortho2(0, winWidth, 0, winHeight);
-
- hmargin = (MARG_NUM * winWidth) / DENOM;
- barWidth = (BAR_NUM * winWidth) / DENOM;
- textHeight = getheight();
- halfTextHeight = textHeight / 2;
-
- if (hmargin * 3 < winHeight) {
- topMargin = hmargin;
- bottomMargin = (hmargin * 3) / 2;
- barHeight = winHeight - topMargin - bottomMargin;
- } else {
- barHeight = winHeight;
- topMargin = bottomMargin = 0;
- }
- labelLeft = winWidth - TEXTWIDTH - SLABELWIDTH;
- lineLeft = (winWidth * LINELEFT_NUM) / DENOM;
- lineRight = labelLeft - winWidth / DENOM;
- labelTop = winHeight - topMargin;
- labelBottom = bottomMargin;
- }
-
- /*
- * void
- * Init(PROGNAME *progNames, long threshHold)
- *
- * Description:
- * Initialize. Call winopen, and call Resize to set global
- * variables.
- *
- * Parameters:
- * progNames List of program names given in -p option
- * threshHold the initial threshhold to use (can be changed
- * later by SetThreshHold)
- */
-
- void
- Init(PROGNAME *progNames, long threshHold)
- {
- char hname[50], title[100];
-
- if (gethostname(hname, sizeof hname) < 0) {
- strcpy(title, "Memory Usage");
- } else {
- sprintf(title, "Memory Usage @ %s", hname);
- }
-
- minsize(MINWIDTH, MINHEIGHT);
- maxsize(MINWIDTH, getgdesc(GD_XPMAX));
- winopen("gmemusage");
- wintitle(title);
- icontitle("gmemusage");
- doublebuffer();
- gconfig();
- Resize();
-
- bgColor = getplanes() < 8 ? BGCOLOR_4BIT : BGCOLOR;
-
- mapcolor(bgColor, 0, 0x24, 0x3f);
-
- color(bgColor);
- clear();
- swapbuffers();
- gflush();
- /*
- * This makes the outlines of the bars match up with the bars
- * themselves.
- */
- glcompat(GLC_OLDPOLYGON, 0);
- memThresh = threshHold;
- drawNames = progNames;
- }
-
- /*
- * static void
- * DrawBar(long top, long height, Colorindex barColor, long margin,
- * long width, long split)
- *
- * Description:
- * Draw one of the memory bars
- *
- * Parameters:
- * top The top of the bar
- * height The height of the bar
- * barColor The color of the bar
- * margin left side of bar
- * width width of bar
- * long split
- */
-
- static void
- DrawBar(long top, long height, Colorindex barColor, long margin,
- long width, long split)
- {
- color(barColor);
- rectfi(margin, top - height, margin + width, top);
- color(BLACK);
- recti(margin, top, margin + width, top - height);
-
- if (split) {
- recti(margin + width - split, top, margin + width, top - height);
- }
- }
-
- /*
- * static void
- * SetupLabels(PROGRAM *usageList, int numBars)
- *
- * Description:
- * Set the labelOffset member of each non-skip element in the
- * list. This is kind of tricky. We want each label to be as
- * close as possible (vertically) to the center of the bar to
- * which it corresponds, while at the same time preventing the
- * labels from overlapping.
- *
- * If there's no extra room, meaning that there are more labels
- * than can fit in the space provided, we spread them evenly to
- * minimize overlap.
- *
- * Otherwise, we know that all the labels can fit without
- * overlapping, but there may be clusters of labels that are too
- * close together. So we locate these clusters, and try to center
- * them with respect to the bars to which they correspond. We
- * check how much extra space is above and below the cluster, and
- * skew either way if there isn't enough for us to center
- * ourselves. Furthermore, once we've set up a cluster we have
- * to go back up the list, pushing the previous labels up if our
- * new cluster location overlaps an old cluster location.
- *
- * The reason that all this works is that we have predetermined
- * that there really is enough space to do this; we always know
- * that our cluster will fit one way or the other, and we won't
- * push labels up off the top of the window because we checked
- * the space first and didn't assume there was more space above
- * us than there actually is.
- *
- * Parameters:
- * usageList list of labels to spread out
- * numBars number of bars in the list
- */
-
- static void
- SetupLabels(PROGRAM *usageList, int numBars)
- {
- int offset;
- float aveSep, foffset;
- int nLabels, top, bottom, extraAbove, extraBelow;
- int nCluster, center, firstCenter, lastCenter;
- PROGRAM *usage, *next, *prev, *elem;
-
- aveSep = (numBars > 1) ?
- (float)(labelTop - labelBottom) / (float)(numBars - 1)
- : labelTop - labelBottom;
-
- /*
- * Spread 'em evenly if there's no extra space. Do the
- * calculations in floating point so we utilize the extra space as
- * well as we can.
- */
- if (aveSep <= textHeight) {
- usage = usageList;
- foffset = labelTop;
- while (usage) {
- if (!usage->skip) {
- usage->labelOffset = foffset;
- foffset -= aveSep;
- }
- usage = usage->next;
- }
- return;
- }
-
- /*
- * If we got here, then there's enough space to have at least
- * textHeight space between each pair of labels. We try our best
- * to keep the labels close vertically to the center of the bars
- * to which they correspond.
- */
- usage = FirstProgram(usageList);
- nLabels = 0;
-
- while (usage) {
- /*
- * Find the extent of this cluster. We consider single labels
- * that have lots of space on either side to be clusters of
- * size one.
- */
- firstCenter = usage->center;
- bottom = firstCenter + halfTextHeight;
- next = NextProgram(usage);
- nCluster = 1;
- lastCenter = usage->center;
- center = usage->center;
- bottom = usage->center - textHeight;
-
- while (next && bottom <= next->center) {
- nCluster++;
- lastCenter = next->center;
- center = lastCenter + (firstCenter - lastCenter) / 2;
- bottom = center - (nCluster * textHeight) / 2;
- next = NextProgram(next);
- }
-
- /*
- * bottom and center have been set below; now figure out where
- * the top is.
- */
- top = center + ((nCluster - 1) * textHeight + 1) / 2;
-
- /*
- * We want to have this cluster extend from top to bottom.
- * Now we calculate how much extra space there is above and
- * below us, and skew the cluster down if there's not enough
- * space above us and up if there's not enough space below us.
- *
- * Remember, there's guaranteed to be enough space *somewhere*
- * for this cluster to fit.
- */
- extraAbove = labelTop - top - textHeight * nLabels;
- extraBelow = bottom - labelBottom - textHeight *
- (numBars - nLabels - nCluster);
-
- if (extraAbove < 0) {
- top += extraAbove;
- } else if (extraBelow < 0) {
- top -= extraBelow;
- }
-
- nLabels += nCluster;
-
- elem = usage;
- offset = top;
-
- /*
- * Set the labelOffsets. The members of the cluster will be
- * exactly textHeight away from one another.
- */
- while (nCluster--) {
- elem->labelOffset = offset;
- offset -= textHeight;
- elem = NextProgram(elem);
- }
-
- /*
- * Remember where we were for the next iteration
- */
- next = elem;
-
- /*
- * Push previous labels up if necessary
- */
- elem = usage;
- prev = PrevProgram(usage);
- while (prev &&
- prev->labelOffset - elem->labelOffset < textHeight) {
- prev->labelOffset = elem->labelOffset + textHeight;
- elem = prev;
- prev = PrevProgram(elem);
- }
-
- usage = next;
- }
- }
-
- /*
- * void
- * DrawLabels(PROGRAM *usageList, SecondType stype)
- *
- * Description:
- * Draw the labels down the right side of the window
- *
- * Parameters:
- * usageList list of bars and labels
- * stype type of secondary labels
- */
-
- void
- DrawLabels(PROGRAM *usageList, SecondType stype)
- {
- PROGRAM *usage = usageList;
- char labelBuf[100];
-
- while (usage) {
- if (!usage->skip) {
- color(barColors[usage->color]);
- /*
- * If there is more than one copy of a program running,
- * denote that with the number of copies running in
- * parentheses.
- */
- if (usage->nProc == 1) {
- sprintf(labelBuf, "%-16.16s: %d K", usage->progName,
- usage->value);
- } else if (usage->nProc < 10) {
- sprintf(labelBuf, "%-12.12s (%d): %d K", usage->progName,
- usage->nProc, usage->value);
- } else {
- sprintf(labelBuf, "%-11.11s (%d): %d K", usage->progName,
- usage->nProc, usage->value);
- }
- /*
- * For some reason, halfTextHeight / 2 looks really nice.
- */
- cmov2i(labelLeft, usage->labelOffset - halfTextHeight / 2);
- charstr(labelBuf);
-
- if (stype != None && usage->secondValue != NOSVAL) {
- sprintf(labelBuf, "%d K", usage->secondValue);
- cmov2i(winWidth - SLABELWIDTH,
- usage->labelOffset - halfTextHeight / 2);
- charstr(labelBuf);
- }
- }
- usage = usage->next;
- }
- }
-
- /*
- * void
- * DrawLines(PROGRAM *usage)
- *
- * Description:
- * Draw the lines from the bars to the labels
- *
- * Parameters:
- * usage List of labels and bars
- */
-
- void
- DrawLines(PROGRAM *usage)
- {
- long pt[2];
- while (usage) {
- if (!usage->skip) {
- color(barColors[usage->color]);
- bgnline();
- pt[0] = lineLeft;
- pt[1] = usage->center;
- v2i(pt);
- pt[0] = lineRight;
- pt[1] = usage->labelOffset /* - halfTextHeight */;
- v2i(pt);
- endline();
- }
- usage = usage->next;
- }
- }
-
- /*
- * void
- * Draw(PROGRAM *usageList, int barTotal, int numBars, char *progName,
- * UsageType type)
- *
- * Description:
- * Draw captions, bars, labels, and lines
- *
- * Parameters:
- * usageList bars and labels to draw
- * barTotal total memory used by bar
- * numBars number of bars
- * progName name of program (if this is memory use within a program)
- * type type of chart we're drawing. Used to select the
- * proper captions
- * stype secondary type of chart, for more captions and labels
- */
-
- void
- Draw(PROGRAM *usageList, int barTotal, int numBars, char *progName,
- UsageType type, SecondType stype)
- {
- long top, height, split;
- int swidth, secondValTotal = 0;
- char buf[100], *str;
- PROGRAM *usage;
-
- if (!progName) {
- color(bgColor);
- clear();
- }
-
- /*
- * Draw a title based on the type of graph
- */
- color(TEXTCOLOR);
- if (progName) {
- sprintf(buf, progTitles[type], progName);
- str = buf;
- } else {
- str = titles[type];
- }
- swidth = strwidth(str);
- cmov2i(winWidth / 2 - swidth / 2,
- winHeight - topMargin / 2 - halfTextHeight);
- charstr(str);
-
- /*
- * Draw the bars
- */
- top = winHeight - topMargin;
-
- usage = usageList;
-
- while (usage) {
- if (!usage->skip) {
- height = (usage->value * barHeight) / barTotal;
- split = usage->value > 0 ?
- (usage->secondValue * barWidth) / usage->value : 0;
- if (split > barWidth || split < 0) {
- split = 0;
- }
- DrawBar(top, height, barColors[usage->color],
- hmargin, barWidth, split);
- usage->top = top;
- usage->height = height;
- usage->center = top - height / 2;
- top -= height;
- secondValTotal += usage->secondValue;
- }
- usage = usage->next;
- }
-
- color(TEXTCOLOR);
- /*
- * Draw the total
- */
- if (!progName && (type == Physical || type == MappedObjects)) {
- sprintf(buf, captions[type], barTotal, barTotal - usageList->value);
- } else {
- sprintf(buf, (progName ? progCaptions : captions)[type], barTotal);
- }
- swidth = strwidth(buf);
- cmov2i(winWidth / 2 - swidth / 2, textHeight * 2 + halfTextHeight);
- charstr(buf);
-
- /*
- * Tell the user how to get help
- */
- str = "Press 'h' for help.";
- swidth = strwidth(str);
- cmov2i(winWidth / 2 - swidth / 2, textHeight);
- charstr(str);
-
- /*
- * Draw the labels and lines
- */
- SetupLabels(usageList, numBars);
- DrawLabels(usageList, stype);
- DrawLines(usageList);
-
- if (stype != None) {
- color(TEXTCOLOR);
- cmov2i(winWidth - SLABELWIDTH,
- winHeight - topMargin / 2 - halfTextHeight);
- charstr(secondLabels[stype]);
-
- cmov2i(winWidth - SLABELWIDTH,
- textHeight * 2 + halfTextHeight);
- sprintf(buf, "%d K", secondValTotal);
- charstr(buf);
- }
-
- swapbuffers();
- gflush();
- }
-
- /*
- * void
- * DrawShadow(PROGRAM *usage, int barTotal, char *progName)
- *
- * Description:
- * Draw shadow bars, so the user can tell how a program's memory
- * use breakdown fits in with the rest of memory. The current
- * program is drawn solid, the rest are just outlines.
- *
- * Parameters:
- * usage shadow usage
- * barTotal total of the bars
- * progName name of the program to draw solid.
- */
-
- void
- DrawShadow(PROGRAM *usage, int barTotal, char *progName)
- {
- long top, height, left;
-
- color(bgColor);
- clear();
-
- color(TEXTCOLOR);
-
- top = winHeight - topMargin - YSHADOWOFF;
- left = hmargin - XSHADOWOFF;
-
- while (usage) {
- if (!usage->skip) {
- height = (usage->value * barHeight) / barTotal;
- (strcmp(usage->progName, progName) == 0 ?
- rectfi : recti)(left, top, left + barWidth, top - height);
- usage->top = top;
- usage->height = height;
- top -= height;
- }
- usage = usage->next;
- }
-
- /*
- * Don't swapbuffers or gflush here; we're depending on a
- * subsequent call to Draw for that.
- */
- }
-
-
- /*
- * char *
- * Select(PROGRAM *usage, long x, long y, int *procMode, int dragging)
- *
- * Description:
- * The user has clicked the mouse. Figure out what he or she has
- * selected.
- *
- * This function helps implement the policy of what kind of
- * display to do by modifying the procMode parameter. What we're
- * implementing is that if we're in procMode and the user clicks
- * anywhere outside the shadow bar, we should go back to regular
- * mode. This may be more convenient than using the space bar,
- * which is the "official" means of return.
- *
- * Parameters:
- * usage List of usage
- * x x coordinate of mouse click
- * y y coordinate of mouse click
- * procMode 1 if we're in procMode, 0 otherwise
- * dragging 1 if we're dragging, 0 otherwise
- *
- * Returns:
- * name of the thing that was clicked on
- */
-
- char *
- Select(PROGRAM *usage, long x, long y, int *procMode, int dragging)
- {
- if (*procMode) {
- if (y < bottomMargin - YSHADOWOFF
- || y > winHeight - topMargin - YSHADOWOFF) {
- if (!dragging) {
- *procMode = 0;
- }
- return NULL;
- }
-
- /*
- * Adjust x coordinate for procMode. The bars will all have
- * the correct top and height for comparison purposes because
- * these got calculated in DrawShadow, but the x has to be
- * adjusted because the comparison code below assumes the bars
- * are drawn in the normal place instead of offset to the
- * left.
- */
- x += XSHADOWOFF;
- }
-
- if (hmargin <= x && x <= hmargin + barWidth) {
- while (usage) {
- if (!usage->skip && !usage->special && y <= usage->top
- && y > usage->top - usage->height) {
- return strdup(usage->progName);
- }
- usage = usage->next;
- }
- } else if (!*procMode && labelLeft <= x && x <= winWidth - hmargin) {
- while (usage) {
- if (!usage->skip && !usage->special && y <=
- usage->labelOffset + halfTextHeight &&
- y > usage->labelOffset - halfTextHeight) {
- return strdup(usage->progName);
- }
- usage = usage->next;
- }
- } else if (!dragging) {
- *procMode = 0;
- }
-
- return NULL;
- }
-
- /*
- * void
- * Help(void)
- *
- * Description:
- * Display some (hopefully) useful information on running
- * gmemusage.
- */
-
- void
- Help(void)
- {
- char *str;
- int swidth, tabStop;
- long textY;
-
- color(bgColor);
- clear();
-
- color(TEXTCOLOR);
- textY = winHeight - textHeight - halfTextHeight;
-
- str = "Command line usage:";
- swidth = strwidth(str);
- cmov2i(MINWIDTH / 2 - swidth / 2, textY);
- charstr(str);
-
- textY -= textHeight + halfTextHeight;
-
- tabStop = strwidth("gmemusage ");
-
- str = "gmemusage [ -i interval ] [ -m | -p | -r | -s ] [ -u ]";
- cmov2i(hmargin, textY);
- charstr(str);
- textY -= textHeight;
-
- cmov2i(hmargin + tabStop, textY);
- charstr("[ -a aiff-file ] [ -g growth-threshhold ]");
- textY -= textHeight;
-
- cmov2i(hmargin + tabStop, textY);
- charstr("[ -t thresh ] [ -d delta ] [ progs ... ]");
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("interval is the polling interval in milliseconds");
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("-m selects Resident Mappings");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("-p selects Physical Memory Breakdown (default)");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("-r selects Resident Sizes of Processes");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("-s selects Total Sizes of Processes");
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("-u forces update of inode lookup table");
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("aiff-file is the sound for program usage");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("growth-threshhold is the minimum increase for usage sounds");
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("thresh is the memory threshhold for displaying");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("individual programs (defaults to 500 K),");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("delta is the amount by which the arrow keys");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("change the threshhold (defaults to 50 K), and");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("progs is a list of programs to view.");
- textY -= textHeight * 2;
-
- str = "Runtime usage:";
- swidth = strwidth(str);
- cmov2i(MINWIDTH / 2 - swidth / 2, textY);
- charstr(str);
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("Click on a bar to view detailed memory usage,");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("and from there press the space bar to return");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("to the overview.");
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("'m' selects Resident Mappings");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("'p' selects Physical Memory Breakdown");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("'r' selects Resident Sizes of Processes");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("'s' selects Total Sizes of Processes");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("'v' cycles through some interesting information");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("'t' prints current information to stdout");
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("up arrow key increases the threshhold");
- textY -= textHeight;
-
- cmov2i(hmargin, textY);
- charstr("down arrow key decreases the threshhold");
- textY -= textHeight + halfTextHeight;
-
- cmov2i(hmargin, textY);
- charstr("escape key exits");
- textY -= textHeight * 3;
-
- str = "See also the gmemusage(1) man page";
- swidth = strwidth(str);
- cmov2i(MINWIDTH / 2 - swidth / 2, textHeight * 2 + halfTextHeight);
- charstr(str);
-
- str = "Press the space bar to return to Usage Viewer";
- swidth = strwidth(str);
- cmov2i(MINWIDTH / 2 - swidth / 2, textHeight);
- charstr(str);
-
- swapbuffers();
- gflush();
- }
-
- /*
- * void
- * SetThreshHold(long thresh)
- *
- * Description:
- * Specify a new threshhold
- *
- * Parameters:
- * thresh the new threshhold
- */
-
- void
- SetThreshHold(long thresh)
- {
- memThresh = thresh;
- }
-
- /*
- * void
- * WaitMessage(char *message)
- *
- * Description:
- * Display a wait message instead of bars
- *
- * Parameters:
- * message the message to display
- * detail another line to display, if not NULL
- */
-
- void
- WaitMessage(char *message, char *detail)
- {
- int swidth;
- int textY;
-
- color(bgColor);
- clear();
-
- color(TEXTCOLOR);
- textY = winHeight / 2 + halfTextHeight;
-
- swidth = strwidth(message);
- cmov2i(winWidth / 2 - swidth / 2, textY);
- charstr(message);
- textY -= textHeight * 2;
-
- if (detail) {
- swidth = strwidth(detail);
- cmov2i(winWidth / 2 - swidth / 2, textY);
- charstr(detail);
- }
-
- swapbuffers();
- gflush();
- }
-